////////////////////////////////////////////////////////////////////////////////
// uftpd is a userspace ftp daemon using qt for network gui and file io.
// Copyright (C) 2008 Tobias Wich
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
////////////////////////////////////////////////////////////////////////////////

///
/// \file session.H
/// \brief Definition of States and the Statemachine.
///

#ifndef __SESSION_H__
#define __SESSION_H__

#include <string>
#include <vector>
#include <map>

#include "ftp_commands.H"

using namespace std;

namespace uftpd {

  class SessionMachine;

  enum StatesE { LOGIN = 0,
		 CMD,
  };

  class AbstractState {
  private:
    static void tokenizeCmd(vector<string> & cmdList, string cmd);
  protected:
    SessionMachine * sm; ///< Session object used to retrieve information like rootpath etc.
    ReplyCodeT mCode; ///< Replycode with 

    AbstractState(SessionMachine * sm) : sm(sm), mCode(FTP_READY) { }
    virtual StatesE processCmd(vector<string> & v) =0;    
    
    void setReplyCode(const ReplyCodeT & code) {
      this->mCode = code;
    }

    SessionMachine * session() {
      return sm;
    }

  public:
    virtual ~AbstractState() { }

    StatesE process(string cmd);

    ReplyCodeT & replyCode() {
      return mCode;
    }

    virtual StatesE returnSelf() const =0;
  };

  class LoginState : public AbstractState {
  private:
    string mUser;

    bool setUser(string userName);
    bool setPass(string password);

  public:
    LoginState(SessionMachine * sm) : AbstractState(sm) { }

    StatesE processCmd(vector<string> & v);
    StatesE returnSelf() const {
      return LOGIN;
    }
  };

  class CmdState : public AbstractState {
  public:
    CmdState(SessionMachine * sm) : AbstractState(sm) { }

    StatesE processCmd(vector<string> & v);
    StatesE returnSelf() const {
      return CMD;
    }
  };

  class SessionMachine {
  private:
    map<StatesE, AbstractState *> mStateMap;
    AbstractState * mCurState;

    inline void setState(StatesE state) {
      mCurState = mStateMap[state];
    }

  public:
    SessionMachine() {
      AbstractState * newState;
      newState = new LoginState(this);
      mStateMap.insert(make_pair(LOGIN, newState));
      newState = new CmdState(this);
      mStateMap.insert(make_pair(CMD, newState));

      setState(LOGIN);
    }

    ~SessionMachine() {
      for (map<StatesE, AbstractState*>::iterator it = mStateMap.begin(); it != mStateMap.end(); it++) {
	delete it->second;
      }
    }

    ReplyCodeT processCmd(string cmd);
  };

}

#endif
